#    FlyBack
#    Copyright (C) 2007 Steve Leach
#
#    This program is free software; you can redistribute it and/or modify
#    it under the terms of the GNU General Public License as published by
#    the Free Software Foundation; either version 2 of the License, or
#    (at your option) any later version.
#
#    This program is distributed in the hope that it will be useful,
#    but WITHOUT ANY WARRANTY; without even the implied warranty of
#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
#    GNU General Public License for more details.
#
#    You should have received a copy of the GNU General Public License along
#    with this program; if not, write to the Free Software Foundation, Inc.,
#    51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.

import pickle
import misc

DEFAULT_EXCLUDES = [
    '/**/.thumbnails/',
    '/**/.mozilla/**/Cache/',
    '/**/.cache/tracker/',
    '/**/.Trash/',
    '/**/.emerald/themecache/',
    '/**/.fontconfig/*.cache*',
    '/**/.java/deployment/cache/',
    '/**/amarok/albumcovers/cache/',
    '/**/amarok/albumcovers/large/',
    '/**/.liferea*/mozilla/liferea/Cache/',
    '/**/.liferea*/cache/',
    '/**/.macromedia/Flash_Player/*SharedObjects/',
    '/**/.macromedia/Macromedia/Flash\ Player/*SharedObjects/',
    '/**/.metacity/sessions/',
    '/**/.nautilus/saved*',
    '/**/.mythtv/osdcache/',
    '/**/.mythtv/themecache/',
    '/**/var/cache/',
    '/**/workspace/.metadata/',
    '/**/.openoffice.org2/user/registry/cache/',
    '/**/.openoffice.org2/user/uno_packages/cache/',
    '/**/.grails/*/scriptCache/',
    '/**/.wine/drive_c/windows/temp/',
    '/cdrom',
    '/dev/',
    '/proc/',
    '/sys/',
    '/tmp/',
    '/mnt/',
    '/media/',
]


class GConfConfig:
    """
    Encapsulation of a GConf configuration for Flyback.
    
    Alternative configuration stores (such as Python cfg files
    can implement the same interface if required. 
    """
    
    DEFAULT_LOCATION="/apps/flyback/"

    def __init__(self, location=DEFAULT_LOCATION):
        try:
            import gconf
        except:
            print 'error: could not find python module gconf'
            sys.exit()

        self.client = gconf.client_get_default()
        self.client.add_dir (location, gconf.CLIENT_PRELOAD_NONE)
        self.location = location
        
    def get_string(self, scheme_id, key, default=None):
        x = self.client.get_string(self.location + scheme_id + '/'  + key)
        if x:
            return x
        else:
            return default

    def set_string(self, scheme_id, key, value):
        self.client.set_string(self.location + scheme_id + '/' + key,value)
        
    def get_list(self, scheme_id, key, default=[]):
        assert(isinstance(default, list))
        x = self.client.get_string(self.location + scheme_id + '/'  + key)
        if x:
            return pickle.loads(x)
        else:
            return default
    
    def set_list(self, scheme_id, key, values):
        self.client.set_string( self.location + scheme_id + '/'  + key, pickle.dumps(values) ) 
    
    def get_bool(self, scheme_id, key, default=False):
        x = self.client.get_bool(self.location + scheme_id + '/'  + key)
        if x:
            return x
        else:
            return default
    
    def set_bool(self, scheme_id, key, value):
        self.client.set_bool(self.location + key,value)

    def get_int(self, scheme_id, key, default=0):
        x = self.client.get_int(self.location + scheme_id + '/'  + key)
        if x!=None:
            return x
        else:
            return default
    
    def set_int(self, scheme_id, key, value):
        self.client.set_int(self.location + scheme_id + '/' + key, value)

    """
    Flushes configuration to disk.
    For the FConfConfig this does nothing, but other config
    implementations may need to do something here.
    """
    def flush(self):
        pass

class TextConfig:
    """
    Encapsulation of a ConfigObj configuration for Flyback.
    
    """

    import os
    
    DEFAULT_LOCATION=os.path.expanduser("~") + "/.flyback.conf"

    def __init__(self, location=DEFAULT_LOCATION):
        from configobj import ConfigObj
        
        self.location = location
        self.storage = ConfigObj(location)
        self.storage.create_empty=True
        
    def get_string(self, scheme_id, key, default=None):
        try:
            x = str(self.storage[key])
            if x:
                return x
            else:
                return default
        except:
            return default

    def set_string(self, scheme_id, key, value):
        self.storage[scheme_id][key] = value
        self.storage.write()
        
    def get_list(self, scheme_id, key, default=[]):
        try:
            x = list(self.storage[scheme_id][key])
            if x:
                return x
            else:
                return default
        except:
            return default
    
    def set_list(self, scheme_id, key, values):
        self.storage[scheme_id][key] = values
        self.storage.write()
    
    def get_bool(self, scheme_id, key, default=False):
        try:
            x = bool(self.storage[scheme_id][key])
            if x:
                return x
            else:
                return default
        except:
            return default
    
    def set_bool(self, scheme_id, key, value):
        self.storage[scheme_id][key] = value
        self.storage.write()

    def get_int(self, scheme_id, key, default=0):
        try:
            x = int(self.storage[scheme_id][key])
            if x:
                return x
            else:
                return default
        except:
            return default
    
    def set_int(self, scheme_id, key, value):
        self.storage[scheme_id][key] = value
        self.storage.write()

    """
    Flushes configuration to disk.
    For the FConfConfig this does nothing, but other config
    implementations may need to do something here.
    """
    def flush(self):
        pass


class _BackupSchemeConfig():
    
    def __init__(self,backend, scheme_id):
        self.backend = backend
        self.scheme_id = str(scheme_id)
        
    # storage location    
    def get_scheme_name(self):
        return self.backend.get_string(self.scheme_id, "scheme_name")

    def set_scheme_name(self, value):
        self.backend.set_string(self.scheme_id, "scheme_name", value)
    
    # storage location    
    def get_storage_location(self):
        return self.backend.get_string(self.scheme_id, "external_storage_location", '/mnt/backup/flyback')

    def set_storage_location(self, value):
        self.backend.set_string(self.scheme_id, "external_storage_location", value)
    
    # storage location type
    def get_storage_type(self):
        return self.backend.get_string(self.scheme_id, "external_storage_location_type")
    
    def set_storage_type(self, value):
        self.backend.set_string(self.scheme_id, "external_storage_location_type", value)
        
    # storage unmout
    def get_storage_unmount(self):
        return self.backend.get_bool(self.scheme_id, "external_storage_location_unmount", False)
    
    def set_storage_unmount(self, value):
        self.backend.set_bool(self.scheme_id, "external_storage_location_unmount", value)
        
    # backup as user
    def get_backup_as_user(self):
        return self.backend.get_bool(self.scheme_id, misc.get_current_username())
    
    def set_backup_as_user(self, value):
        self.backend.set_bool(self.scheme_id, "backup_as_user", value)
        
    # included directories
    def get_included_dirs(self):
        return self.backend.get_list(self.scheme_id, "included_dirs",[ '/'])
    
    def set_included_dirs(self, value):
        self.backend.set_list(self.scheme_id, "included_dirs", value)
        
    # only one file system
    def get_only_one_file_system(self):
        return self.backend.get_bool(self.scheme_id, 'prefs_only_one_file_system_checkbutton', True)
    
    def set_only_one_file_system(self, value):
        self.backend.set_bool(self.scheme_id, "prefs_only_one_file_system_checkbutton", value)
        
    # excluded paterns
    def get_excluded_patters(self):
        return self.backend.get_list(self.scheme_id, 'excluded_patterns', DEFAULT_EXCLUDES)
    
    def set_excluded_patters(self, value):
        self.backend.set_list(self.scheme_id, "excluded_patterns", value)
        
    # configure crontab
    def get_configure_crontab(self):
        return self.backend.get_string(self.scheme_id, 'crontab')
    
    def set_configure_crontab(self, value):
        self.backend.set_string(self.scheme_id, "crontab", value)
        
    # auto clean old backups for space
    def get_autoclean_for_space(self):
        return self.backend.get_bool(self.scheme_id, 'pref_delete_backups_free_space', True)
    
    def set_autoclean_for_space(self, value):
        self.backend.set_bool(self.scheme_id, "pref_delete_backups_free_space", value)
        
    # auto clean old backups for space quantity
    def get_autoclean_for_space_qty(self):
        return self.backend.get_int(self.scheme_id, 'pref_delete_backups_free_space_qty', 1)
    
    def set_autoclean_for_space_qty(self, value):
        self.backend.set_int(self.scheme_id, "pref_delete_backups_free_space_qty", value)
        
    # auto clean old backups for space units
    def get_autoclean_for_space_units(self):
        return self.backend.get_string(self.scheme_id, 'pref_delete_backups_free_space_unit', 'GB')
    
    def set_autoclean_for_space_units(self, value):
        self.backend.set_string(self.scheme_id, "pref_delete_backups_free_space_unit", value)
        
    # auto clean old backups after time
    def get_autoclean_after_time(self):
        return self.backend.get_bool(self.scheme_id, 'pref_delete_backups_after', True)
    
    def set_autoclean_after_time(self, value):
        self.backend.set_bool(self.scheme_id, "pref_delete_backups_after", value)
        
    # auto clean old backups after time quantity
    def get_autoclean_after_time_qty(self):
        return self.backend.get_int(self.scheme_id, 'pref_delete_backups_after_qty', 1)
    
    def set_autoclean_after_time_qty(self, value):
        self.backend.set_int(self.scheme_id, "pref_delete_backups_after_qty", value)
        
    # auto clean old backups after time units
    def get_autoclean_after_time_units(self):
        return self.backend.get_string(self.scheme_id, 'pref_delete_backups_after_unit', 'years')
    
    def set_autoclean_after_time_units(self, value):
        self.backend.set_string(self.scheme_id, "pref_delete_backups_after_unit", value)
        

class Config():
    FILE, GCONF = range(0,2)
    
    def __init__(self,type=GCONF, location=None):
        self.backend = None
        
        if (type == Config.GCONF):
            if location :
                self.backend = GConfConfig(location)
            else :
                self.backend = GConfConfig()
        else:
            if location :
                self.backend = TextConfig(location)
            else :
                self.backend = TextConfig()
        
        self.main_scheme_id = 'main'
                
    # auto clean old backups after time units
    def get_backup_schemes(self):
        """ Get backup schemes ids
        
        return
            A list of the backup scheme ids
            
        """
        
        return self.backend.get_list(self.main_scheme_id, "backup_schemes")
    
    def create_backup_scheme_config(self, scheme_id=None):
        """ Add and return a new backup scheme config
        
        """
        if scheme_id == None:
            next_id = max(self.get_backup_schemes(), key=int) + 1
        else:
            next_id = scheme_id
        
        backup_scheme =  _BackupSchemeConfig(self.backend, next_id)
        
        backup_scheme_ids = self.backend.get_list(self.main_scheme_id, "backup_schemes")
        backup_scheme_ids.append(next_id)
        self.backend.set_list(self.main_scheme_id, "backup_schemes", backup_scheme_ids)
        
        return backup_scheme
              
    def get_backup_scheme_config(self, scheme_id):
        """ return a backup scheme config
        
        """
        assert(scheme_id in self.get_backup_schemes())

        return _BackupSchemeConfig(self.backend, scheme_id)
              
     # show output
    def is_show_output(self):
        return self.backend.get_bool(self.main_scheme_id, "show_output")
        
    def set_show_output(self,value):
        self.backend.set_bool(self.main_scheme_id, "show_output", value)
        
    # show opengl
    def is_show_opengl(self):
        return self.backend.get_bool(self.main_scheme_id, "show_opengl")

    def set_show_opengl(self,value):
        self.backend.set_bool(self.main_scheme_id, "show_opengl", value)
        
    # show hidden files
    def is_show_hidden_files(self):
        return self.backend.get_bool(self.main_scheme_id, "show_hidden_files")
    
    def set_show_hidden_files(self,value):
        self.backend.set_bool(self.main_scheme_id, 'show_hidden_files',value)
    
    # sort directories first
    def is_sort_dirs_first(self):
        return self.backend.get_bool(self.main_scheme_id, "sort_dirs_first")
    
    def set_sort_dirs_first(self,value):
        self.backend.set_bool(self.main_scheme_id, 'sort_dirs_first',value)
        
               
        
    
    

        
import unittest

KEY = "/apps/flyback/test/x"

class TestCase(unittest.TestCase):
    
    def setUp(self):
        unittest.TestCase.setUp(self)
        self.cfg = GConfConfig()
    
    def tearDown(self):
        unittest.TestCase.tearDown(self)
        self.cfg.set_string(KEY, "")
        
    def testSetGetString(self):
        self.cfg.set_string(KEY,"abc")
        assert self.cfg.get_string(KEY) == "abc"

    def testSetGetStringList(self):
        vals = ["abc","xyz"]
        self.cfg.set_string_list(KEY, vals)
        assert len(self.cfg.get_string_list(KEY)) == 2
        assert self.cfg.get_string_list(KEY)[0] == "abc"
        assert self.cfg.get_string_list(KEY)[1] == "xyz"
        
    def testSetGetFlag(self):
        self.cfg.set_flag(KEY, True)
        assert self.cfg.get_flag(KEY) == True

    def testSetGetInt(self):
        self.cfg.set_int(KEY, 12321)
        assert self.cfg.get_int(KEY) == 12321
        
if __name__ == '__main__':
    unittest.main()

